package com.ngds.library.downloadcenter;

import android.app.DownloadManager.Request;
import android.content.*;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * AppDownloadHelperImpl
 * <p/>
 * Description:实现下载中心接口与功能
 * <ul>
 * <strong>Get download info</strong>
 * <li>{@link #getStatusById(long)} get download status</li>
 * <li>{@link #getDownloadBytes(long)} get downloaded byte, total byte</li>
 * <li>{@link #getBytesAndStatus(long)} get downloaded byte, total byte and download status</li>
 * <li>{@link #getFileName(long)} get download file name</li>
 * <li>{@link #getUri(long)} get download uri</li>
 * <li>{@link #getReason(long)} get failed code or paused reason</li>
 * <li>{@link #getPausedReason(long)} get paused reason</li>
 * <li>{@link #getErrorCode(long)} get failed error code</li>
 * </ul>
 * <ul>
 * <strong>Operate download</strong>
 * <li>{@link #pauseDownload(long...)} pause download. need pauseDownload(long...) method in {@link android.app.DownloadManager}</li>
 * <li>{@link #resumeDownload(long...)} resume download. need resumeDownload(long...) method in {@link android.app.DownloadManager}</li>
 * </ul>
 * <ul>
 * <strong>RequestPro</strong>
 * <li>{@link com.ngds.library.downloadcenter.AppDownloadHelperImpl.RequestPro#setNotiClass(String)} set noti class</li>
 * <li>{@link com.ngds.library.downloadcenter.AppDownloadHelperImpl.RequestPro#setNotiExtras(String)} set noti extras</li>
 * </ul>
 */
public class AppDownloadHelperImpl implements AppDownloadHelper {
    private static final String DOWNLOAD_ENV_SETTING_TAG = "DownloadEnvironmentSettings";
    public static final Uri CONTENT_URI = Downloads.Impl.CONTENT_URI;
    public static final String COLUMN_LOCAL_FILENAME = "local_filename";

    public static final String TAG = "DownloadManagerPro";

    public static final String METHOD_NAME_PAUSE_DOWNLOAD = "pauseDownload";
    public static final String METHOD_NAME_RESUME_DOWNLOAD = "resumeDownload";

    private static boolean isInitPauseDownload = false;
    private static boolean isInitResumeDownload = false;

    private static Method pauseDownload = null;
    private static Method resumeDownload = null;

    private AppDownloadManager downloadManager;
    private static AppDownloadHelperImpl sInstance;

    private AppDownloadHelperImpl(Context context) {
        this.downloadManager = AppDownloadManager.getDownloadManagerService(context);
    }

    private AppDownloadHelperImpl(AppDownloadManager downloadManager) {
        this.downloadManager = downloadManager;
    }

    public static AppDownloadHelper getInstance(Context context) {
        if (null == sInstance) {
            sInstance = new AppDownloadHelperImpl(context);
        }
        return sInstance;
    }

    /**
     * get download status
     *
     * @param downloadId
     * @return
     */
    public int getStatusById(long downloadId) {
        return getInt(downloadId, AppDownloadManager.COLUMN_STATUS);
    }

    /**
     * get downloaded byte, total byte
     *
     * @param downloadId
     * @return a int array with two elements
     * <ul>
     * <li>result[0] represents downloaded bytes, This will initially be -1.</li>
     * <li>result[1] represents total bytes, This will initially be -1.</li>
     * </ul>
     */
    /*public int[] getDownloadBytes(long downloadId) {
        int[] bytesAndStatus = getBytesAndStatus(downloadId);
        return new int[]{bytesAndStatus[0], bytesAndStatus[1]};
    }*/

    /**
     * get downloaded byte, total byte and download status
     *
     * @param downloadId
     * @return a int array with three elements
     * <ul>
     * <li>result[0] represents downloaded bytes, This will initially be -1.</li>
     * <li>result[1] represents total bytes, This will initially be -1.</li>
     * <li>result[2] represents download status, This will initially be 0.</li>
     * </ul>
     */
    public DownloadBytesAndStatusWrapper getBytesAndStatus(long downloadId) {
        DownloadBytesAndStatusWrapper bytesAndStatusWapper = null;
        AppDownloadManager.Query query = new AppDownloadManager.Query().setFilterById(downloadId);
        Cursor c = null;
        try {
            c = downloadManager.query(query);
            if (c != null && c.moveToFirst()) {
                bytesAndStatusWapper = new DownloadBytesAndStatusWrapper(c.getInt(
                    c.getColumnIndexOrThrow(AppDownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)),
                    c.getInt(c.getColumnIndexOrThrow(AppDownloadManager.COLUMN_TOTAL_SIZE_BYTES)),
                    generateCurrectDownloadStatu(
                        c.getInt(c.getColumnIndex(AppDownloadManager.COLUMN_STATUS)), downloadId));
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return bytesAndStatusWapper;
    }

    public DownloadBytesAndStatusWrapper getBytesAndStatus(String url) {
        DownloadBytesAndStatusWrapper bytesAndStatusWapper = null;
        AppDownloadManager.Query query = new AppDownloadManager.Query().setFilterByUrl(url);
        Cursor c = null;
        try {
            c = downloadManager.query(query);
            if (c != null && c.moveToFirst()) {
                long downloaderId =
                    c.getLong(c.getColumnIndexOrThrow(AppDownloadManager.COLUMN_ID));
                bytesAndStatusWapper = new DownloadBytesAndStatusWrapper(c.getInt(
                    c.getColumnIndexOrThrow(AppDownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)),
                    c.getInt(c.getColumnIndexOrThrow(AppDownloadManager.COLUMN_TOTAL_SIZE_BYTES)),
                    generateCurrectDownloadStatu(
                        c.getInt(c.getColumnIndex(AppDownloadManager.COLUMN_STATUS)),
                        downloaderId));
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return bytesAndStatusWapper;
    }

    private Integer generateCurrectDownloadStatu(int downloadStatus, long downloadId) {
        if (downloadStatus == AppDownloadManager.STATUS_RUNNING && !isInQueue(downloadId)) {
            return AppDownloadManager.STATUS_PENDING;
        }
        return downloadStatus;
    }


    /**
     * get downloaded byte, total byte and download status
     *
     * @param downloadIds
     * @return a int array with three elements
     * <ul>
     * <li>result[0] represents downloaded bytes, This will initially be -1.</li>
     * <li>result[1] represents total bytes, This will initially be -1.</li>
     * <li>result[2] represents download status, This will initially be 0.</li>
     * </ul>
     */
    public List<DownloadBytesAndStatusWrapper> getBytesAndStatus(long... downloadIds) {
        if (null == downloadIds || downloadIds.length <= 0) {
            return null;
        }

        List<DownloadBytesAndStatusWrapper> downloadBytesAndStatusWrappers =
            new ArrayList<DownloadBytesAndStatusWrapper>();

        AppDownloadManager.Query query = new AppDownloadManager.Query().setFilterById(downloadIds);
        Cursor c = null;
        try {
            c = downloadManager.query(query);
            for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
                DownloadBytesAndStatusWrapper bytesAndStatusWapper =
                    new DownloadBytesAndStatusWrapper(c.getInt(
                        c.getColumnIndexOrThrow(AppDownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)),
                        c.getInt(
                            c.getColumnIndexOrThrow(AppDownloadManager.COLUMN_TOTAL_SIZE_BYTES)),
                        generateCurrectDownloadStatu(
                            c.getInt(c.getColumnIndex(AppDownloadManager.COLUMN_STATUS)),
                            downloadIds[c.getPosition()]));
                downloadBytesAndStatusWrappers.add(bytesAndStatusWapper);
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return downloadBytesAndStatusWrappers;
    }


    /**
     * pause download
     *
     * @param ids the IDs of the downloads to be paused
     * @return the number of downloads actually paused, -1 if exception or method not exist
     */
    public int pauseDownload(long... ids) {
        initPauseMethod();
        if (pauseDownload != null) {
            try {
                return ((Integer) pauseDownload.invoke(downloadManager, ids)).intValue();
            } catch (Exception e) {
                /**
                 * accept all exception, include ClassNotFoundException, NoSuchMethodException,
                 * InvocationTargetException, NullPointException
                 */
                e.printStackTrace();
            }
        }
        return -1;
    }

    /**
     * resume download
     *
     * @param ids the IDs of the downloads to be resumed
     * @return the number of downloads actually resumed, -1 if exception or method not exist
     */
    public int resumeDownload(long... ids) {
        initResumeMethod();
        if (resumeDownload != null) {
            try {
                return ((Integer) resumeDownload.invoke(downloadManager, ids)).intValue();
            } catch (Exception e) {
                /**
                 * accept all exception, include ClassNotFoundException, NoSuchMethodException,
                 * InvocationTargetException, NullPointException
                 */
                e.printStackTrace();
            }
        }
        return -1;
    }

    /**
     * restart download
     *
     * @param ids
     */
    public void restartDownload(long... ids) throws IllegalArgumentException {
        downloadManager.restartDownload(ids);
    }

    /**
     * whether exist pauseDownload and resumeDownload method in {@link android.app.DownloadManager}
     *
     * @return
     */
    public static boolean isExistPauseAndResumeMethod() {
        initPauseMethod();
        initResumeMethod();
        return pauseDownload != null && resumeDownload != null;
    }

    private static void initPauseMethod() {
        if (!isInitPauseDownload) {
            isInitPauseDownload = true;
            try {
                pauseDownload =
                    AppDownloadManager.class.getMethod(METHOD_NAME_PAUSE_DOWNLOAD, long[].class);
            } catch (Exception e) {
                // accept all exception
                e.printStackTrace();
            }
        }
    }

    private static void initResumeMethod() {
        if (!isInitResumeDownload) {
            isInitResumeDownload = true;
            try {
                resumeDownload =
                    AppDownloadManager.class.getMethod(METHOD_NAME_RESUME_DOWNLOAD, long[].class);
            } catch (Exception e) {
                // accept all exception
                e.printStackTrace();
            }
        }
    }

    /**
     * get download file name
     *
     * @param downloadId
     * @return
     */
    public String getFileName(long downloadId) {
        return getString(downloadId, AppDownloadManager.COLUMN_LOCAL_FILENAME);
    }

    @Override
    public String getDownloadUrl(long downloadId) {
        return getString(downloadId, AppDownloadManager.COLUMN_URI);
    }

    /**
     * get download uri
     *
     * @param downloadId
     * @return
     */
    public String getUri(long downloadId) {
        return getString(downloadId, AppDownloadManager.COLUMN_URI);
    }

    /**
     * get failed code or paused reason
     *
     * @param downloadId
     * @return <ul>
     * <li>if status of downloadId is {@link com.ngds.library.downloadcenter.AppDownloadManager#STATUS_PAUSED}, return {@link #getPausedReason(long)}</li>
     * <li>if status of downloadId is {@link com.ngds.library.downloadcenter.AppDownloadManager#STATUS_FAILED}, return {@link #getErrorCode(long)}</li>
     * <li>if status of downloadId is neither {@link com.ngds.library.downloadcenter.AppDownloadManager#STATUS_PAUSED} nor
     * {@link com.ngds.library.downloadcenter.AppDownloadManager#STATUS_FAILED}, return 0</li>
     * </ul>
     */
    public int getReason(long downloadId) {
        return getInt(downloadId, AppDownloadManager.COLUMN_REASON);
    }

    /**
     * get paused reason
     *
     * @param downloadId
     * @return <ul>
     * <li>if status of downloadId is {@link com.ngds.library.downloadcenter.AppDownloadManager#STATUS_PAUSED}, return one of
     * {@link com.ngds.library.downloadcenter.AppDownloadManager#PAUSED_WAITING_TO_RETRY}<br/>
     * {@link com.ngds.library.downloadcenter.AppDownloadManager#PAUSED_WAITING_FOR_NETWORK}<br/>
     * {@link com.ngds.library.downloadcenter.AppDownloadManager#PAUSED_QUEUED_FOR_WIFI}<br/>
     * {@link com.ngds.library.downloadcenter.AppDownloadManager#PAUSED_UNKNOWN}</li>
     * <li>else return {@link com.ngds.library.downloadcenter.AppDownloadManager#PAUSED_UNKNOWN}</li>
     * </ul>
     */
    public int getPausedReason(long downloadId) {
        return getInt(downloadId, AppDownloadManager.COLUMN_REASON);
    }

    public String getDescription(long downloadId) {
        return getString(downloadId, AppDownloadManager.COLUMN_DESCRIPTION);
    }


    /**
     * get failed error code
     *
     * @param downloadId
     * @return one of {@link com.ngds.library.downloadcenter.AppDownloadManager#*}
     */
    public int getErrorCode(long downloadId) {
        return getInt(downloadId, AppDownloadManager.COLUMN_REASON);
    }

    public void deleteDownload(long... ids) {
        downloadManager.remove(ids);
    }

    public static class RequestPro extends AppDownloadManager.Request {

        public static final String METHOD_NAME_SET_NOTI_CLASS = "setNotiClass";
        public static final String METHOD_NAME_SET_NOTI_EXTRAS = "setNotiExtras";

        private static boolean isInitNotiClass = false;
        private static boolean isInitNotiExtras = false;

        private static Method setNotiClass = null;
        private static Method setNotiExtras = null;

        /**
         * @param uri the HTTP URI to download.
         */
        public RequestPro(Uri uri) {
            super(uri);
        }

        /**
         * set noti class, only init once
         *
         * @param className full class name
         */
        public void setNotiClass(String className) {
            synchronized (this) {

                if (!isInitNotiClass) {
                    isInitNotiClass = true;
                    try {
                        setNotiClass =
                            Request.class.getMethod(METHOD_NAME_SET_NOTI_CLASS, CharSequence.class);
                    } catch (Exception e) {
                        // accept all exception
                        e.printStackTrace();
                    }
                }
            }

            if (setNotiClass != null) {
                try {
                    setNotiClass.invoke(this, className);
                } catch (Exception e) {
                    /**
                     * accept all exception, include ClassNotFoundException, NoSuchMethodException,
                     * InvocationTargetException, NullPointException
                     */
                    e.printStackTrace();
                }
            }
        }

        /**
         * set noti extras, only init once
         *
         * @param extras
         */
        public void setNotiExtras(String extras) {
            synchronized (this) {

                if (!isInitNotiExtras) {
                    isInitNotiExtras = true;
                    try {
                        setNotiExtras = Request.class
                            .getMethod(METHOD_NAME_SET_NOTI_EXTRAS, CharSequence.class);
                    } catch (Exception e) {
                        // accept all exception
                        e.printStackTrace();
                    }
                }
            }

            if (setNotiExtras != null) {
                try {
                    setNotiExtras.invoke(this, extras);
                } catch (Exception e) {
                    /**
                     * accept all exception, include ClassNotFoundException, NoSuchMethodException,
                     * InvocationTargetException, NullPointException
                     */
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * get string column
     *
     * @param downloadId
     * @param columnName
     * @return
     */
    private String getString(long downloadId, String columnName) {
        AppDownloadManager.Query query = new AppDownloadManager.Query().setFilterById(downloadId);
        String result = null;
        Cursor c = null;
        try {
            c = downloadManager.query(query);
            if (c != null && c.moveToFirst()) {

                //                result = c.getString(c.getColumnIndexOrThrow(columnName));
                result = c.getString(c.getColumnIndex(columnName));
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return result;
    }

    /**
     * get int column
     *
     * @param downloadId
     * @param columnName
     * @return
     */
    private int getInt(long downloadId, String columnName) {
        AppDownloadManager.Query query = new AppDownloadManager.Query().setFilterById(downloadId);
        int result = -1;
        Cursor c = null;
        try {
            c = downloadManager.query(query);
            if (c != null && c.moveToFirst()) {
                result = c.getInt(c.getColumnIndex(columnName));
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return result;
    }

    public boolean isDownloading(int downloadStatus) {
        return downloadStatus == AppDownloadManager.STATUS_RUNNING
            || downloadStatus == AppDownloadManager.STATUS_PAUSED
            || downloadStatus == AppDownloadManager.STATUS_PENDING
            || downloadStatus == AppDownloadManager.STATUS_FAILED;
    }

    public boolean isDownloadedSuc(int downloadStatus) {
        return downloadStatus == AppDownloadManager.STATUS_SUCCESSFUL;
    }

    @Override
    public boolean isDownloadedSuc(String url) {
        DownloadBytesAndStatusWrapper bytesAndStatusWrapper = getBytesAndStatus(url);
        return null != bytesAndStatusWrapper && bytesAndStatusWrapper.isProgressSuccessed();
    }

    public boolean isDownloadedSuc(long downloadId) {
        DownloadBytesAndStatusWrapper bytesAndStatusWapper = getBytesAndStatus(downloadId);
        if (null == bytesAndStatusWapper) {
            return false;
        }
        if (isDownloadedSuc(bytesAndStatusWapper.getDownloadStatus())
            && bytesAndStatusWapper.getDownloadBytes() == bytesAndStatusWapper.getTotalBytes()) {
            return true;
        }
        return false;
    }

    public String getTitle(long downloadId) {
        return getString(downloadId, Downloads.Impl.COLUMN_TITLE);
    }

    public long getDownloaderId(Cursor cursor) throws IllegalArgumentException {
        if (null == cursor) {
            throw new IllegalArgumentException("cursor is null");
        }
        return cursor.getLong(cursor.getColumnIndexOrThrow(Downloads.Impl._ID));
    }

    public boolean isStartDirectly(long downloadId) {
        return getInt(downloadId, Downloads.Impl.COLUMN_IS_START_DIRETLY) != 0;
    }

    public String getDataPath(long downloadId) {
        return getString(downloadId, AppDownloadManager.COLUMN_LOCAL_FILENAME);
    }

    public String getErrorMsg(long downloadId) {
        return getString(downloadId, Downloads.Impl.COLUMN_ERROR_MSG);
    }


    /**
     * 设置下载条件（只能在wify条件下载或者亦可）
     *
     * @param context
     * @param isWifyOnly
     */
    public void changeDownloadNetSetting(Context context, boolean isWifyOnly) {
        ContentResolver cr = context.getContentResolver();
        ContentValues cv = new ContentValues();
        cv.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES,
            isWifyOnly ?
                AppDownloadManager.Request.NETWORK_WIFI :
                AppDownloadManager.Request.NETWORK_WIFI
                    | AppDownloadManager.Request.NETWORK_MOBILE);
        cr.update(Downloads.Impl.CONTENT_URI, cv, null, null);
    }

    @Override
    public int getCurrentUserDownloadSettings(Context context) {
        SharedPreferences sharedPreferences =
            context.getSharedPreferences(DOWNLOAD_ENV_SETTING_TAG, 0);
        return sharedPreferences
            .getInt(DOWNLOAD_ENV_SETTING_TAG, DownloadNetEnvironmentSettings.AUTO_SWITCH);
    }

    @Override
    public void setDownloadSettings(Context context, int settting) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(TAG, 0);
        sharedPreferences.edit().putInt(TAG, settting).commit();
        boolean isWifyOnly = (settting == DownloadNetEnvironmentSettings.WIFY_ONLY);
        AppDownloadHelperImpl.getInstance(context).changeDownloadNetSetting(context, isWifyOnly);
    }

    @Override
    public void setDescription(Context context, String description, String url) {
        ContentResolver cr = context.getContentResolver();
        ContentValues cv = new ContentValues();
        cv.put(Downloads.Impl.COLUMN_DESCRIPTION, description);
        cr.update(Downloads.Impl.CONTENT_URI, cv, Downloads.Impl.COLUMN_URI + "=?",
            new String[] {url});
    }

    @Override
    public String getDescription(Context context, String url) {
        String description = null;
        AppDownloadManager.Query query = new AppDownloadManager.Query().setFilterByUrl(url);
        Cursor c = null;
        try {
            c = downloadManager.query(query);
            if (c != null && c.moveToFirst()) {
                description =
                    c.getString(c.getColumnIndexOrThrow(AppDownloadManager.COLUMN_DESCRIPTION));
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return description;
    }

    public void updateDownloadUrl(Context context, long downloaderId, String newUrl) {
        ContentResolver cr = context.getContentResolver();
        ContentValues cv = new ContentValues();
        cv.put(Downloads.Impl.COLUMN_URI, newUrl);
        cr.update(Downloads.Impl.CONTENT_URI, cv, Downloads.Impl._ID + "=?",
            new String[] {String.valueOf(downloaderId)});
    }

    /**
     * 根据Id判断是否在下载队列中
     *
     * @param downloadId
     * @return
     */
    public boolean isInQueue(long downloadId) {
        return DownloadHandler.getInstance().isInProcessing(downloadId);
    }


    /**
     * 创建并开始下载
     *
     * @param context
     * @param effectiveUrl
     * @param fileDir
     * @param fileName
     * @param isNotificationVisible       是否 显示在通知栏上
     * @param downloadEnvironmentSettings 下载环境条件：只有在wify下可用以及都可以使用
     * @param description                 下载备注
     * @param isStartDirectly             是否直接启动
     * @return
     * @throws com.ngds.library.downloadcenter.DownloadError
     */
    public long createAndStartDownload(Context context, String effectiveUrl, String fileDir,
        String fileName, boolean isNotificationVisible, int downloadEnvironmentSettings,
        String description, boolean isStartDirectly) throws DownloadStopedException {
        DownloadBytesAndStatusWrapper downloadBytesAndStatusWrapper =
            getBytesAndStatus(effectiveUrl);
        if (null != downloadBytesAndStatusWrapper) {
            if (Constants.LOGVV) {
                Log.d(TAG, "this url is already in progress");
            }
            return -1;
        }
        File file = new File(fileDir);
        file.mkdirs();
        if (!file.isDirectory()) {
            throw new DownloadError(Downloads.Impl.STATUS_FILE_ERROR, "不是一个有效的文件目录");
        }
        AppDownloadManager.Request request = new AppDownloadManager.Request(
            Uri.parse(effectiveUrl));
        request.setDestinationInExternalFilesDir(context, fileDir, fileName);
        request.setDescription(description);
        request.setTitle(fileName);
        request.setNotificationVisibility(isNotificationVisible ?
            AppDownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED :
            AppDownloadManager.Request.VISIBILITY_HIDDEN);
        request.setAllowedNetworkTypes(
            downloadEnvironmentSettings == DownloadNetEnvironmentSettings.WIFY_ONLY ?
                AppDownloadManager.Request.NETWORK_WIFI :
                AppDownloadManager.Request.NETWORK_WIFI
                    | AppDownloadManager.Request.NETWORK_MOBILE);
        request.setIsStartDirectly(isStartDirectly);
        return AppDownloadManager.getDownloadManagerService(context).enqueue(request);
    }


    public long createAndStartDownload(Context context, String effectiveUrl, String fileDir,
        String fileName) throws DownloadStopedException {
        return createAndStartDownload(context, effectiveUrl, fileDir, fileName, false,
            DownloadNetEnvironmentSettings.AUTO_SWITCH, null, false);
    }

    public long createAndStartDownload(Context context, String effectiveUrl, String fileDir,
        String fileName, boolean isStartDirectly) throws DownloadStopedException {
        return createAndStartDownload(context, effectiveUrl, fileDir, fileName, false,
            getCurrentUserDownloadSettings(context), null, isStartDirectly);
    }

    public long createAndStartDownloadWithNotification(Context context, String effectiveUrl,
        String fileDir, String fileName) throws DownloadStopedException {
        return createAndStartDownload(context, effectiveUrl, fileDir, fileName, true,
            DownloadNetEnvironmentSettings.AUTO_SWITCH, null, false);
    }

    /**
     * 根据下载状态获取下载器游标
     *
     * @param isDownloadFinished
     * @return
     */
    public Cursor queryDownloaderByStatus(boolean isDownloadFinished) {
        AppDownloadManager.Query query = new AppDownloadManager.Query();
        if (isDownloadFinished) {
            query.setFilterByStatus(AppDownloadManager.STATUS_SUCCESSFUL);
        } else {
            query.setFilterByStatus(
                AppDownloadManager.STATUS_PENDING | AppDownloadManager.STATUS_PAUSED
                    | AppDownloadManager.STATUS_RUNNING | AppDownloadManager.STATUS_FAILED);
        }
        query.orderBy(AppDownloadManager.COLUMN_ID, AppDownloadManager.Query.ORDER_DESCENDING);
        return downloadManager.query(query);
    }

    public int getDownloadingCount() {
        AppDownloadManager.Query query = new AppDownloadManager.Query();
        query.setFilterByStatus(AppDownloadManager.STATUS_RUNNING);
        query.orderBy(AppDownloadManager.COLUMN_ID, AppDownloadManager.Query.ORDER_DESCENDING);
        Cursor cursor = downloadManager.query(query);
        if (null == cursor) {
            return 0;
        }
        int downloadingCount = cursor.getCount();
        cursor.close();

        return downloadingCount;

    }

    /**
     * 根据下载器id获取下载器游标
     *
     * @param ids
     * @return
     */
    public Cursor queryDownloaderByStatus(long... ids) {
        AppDownloadManager.Query query = new AppDownloadManager.Query();
        query.setFilterById(ids);
        query.orderBy(AppDownloadManager.COLUMN_ID, AppDownloadManager.Query.ORDER_DESCENDING);
        return downloadManager.query(query);
    }

    /**
     * 获取正在下载的任务个数
     *
     * @return
     */
    public int getNotFinishedCount() {
        Cursor cursor = queryDownloaderByStatus(false);
        int downloadingCount = cursor.getCount();
        if (null != cursor) {
            cursor.close();
        }
        return downloadingCount;
    }

    /**
     * 发送已经下载完成的通知
     *
     * @param downloadId
     * @param context
     */
    public void sendDownloadedSucBroad(long downloadId, Context context) {
        Intent intent = new Intent();
        intent = new Intent(ACTION_DOWNLOAD_COMPLETE);
        //        intent.setPackage(getString(downloadId, Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE));
        intent.setPackage(context.getPackageName());
        intent.putExtra(EXTRA_DOWNLOAD_ID, downloadId);
        context.sendBroadcast(intent);
    }

    public void pauseAllDownload() {
        //        AppDownloadManager.Query query = new AppDownloadManager.Query();
        //        query.setFilterByStatus(AppDownloadManager.STATUS_PENDING | AppDownloadManager.STATUS_PAUSED | AppDownloadManager.STATUS_RUNNING | AppDownloadManager.STATUS_FAILED);
        //        query.orderBy(AppDownloadManager.COLUMN_ID, AppDownloadManager.Query.ORDER_DESCENDING);
        //        Cursor cursor = downloadManager.query(query);
        Cursor cursor = queryDownloaderByStatus(false);
        if (null == cursor) {
            return;
        }
        try {
            long[] downloaderIds = new long[cursor.getCount()];
            int i = 0;
            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                long downloaderId =
                    cursor.getLong(cursor.getColumnIndex(AppDownloadManager.COLUMN_ID));
                downloaderIds[i++] = downloaderId;
            }
            pauseDownload(downloaderIds);
        } finally {
            cursor.close();
        }
    }

    public void exit() {
        pauseAllDownload();
    }

    public void start() {
        startUnfinishedDownload();
    }

    private void startUnfinishedDownload() {
        Cursor cursor = queryDownloaderByStatus(false);
        if (null == cursor) {
            return;
        }
        try {
            long[] downloaderIds = new long[cursor.getCount()];
            int i = 0;
            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                long downloaderId =
                    cursor.getLong(cursor.getColumnIndex(AppDownloadManager.COLUMN_ID));
                downloaderIds[i++] = downloaderId;
            }
            resumeDownload(downloaderIds);
        } finally {
            cursor.close();
        }
    }
}
